﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TableDependency.Abstracts;
using TableDependency.Enums;
using TableDependency.EventArgs;

namespace TableDependency.SqlClient.Where.IntegrationTests
{
    public class TestDateTimeSqlServerModel
    {
        public int Id { get; set; }
        public DateTime Start { get; set; }
    }

    [TestClass]
    public class IntegrationTestDateTime
    {
        private int _insertedId;
        private int _deletedId;
        private readonly DateTime _now = DateTime.Now;
        private static readonly string ConnectionString = ConfigurationManager.ConnectionStrings["SqlServerConnectionString"].ConnectionString;
        private const string TableName = "TestDateTimeSqlServerModel";
        private static int _counter;
        private static readonly Dictionary<string, Tuple<TestDateTimeSqlServerModel, TestDateTimeSqlServerModel>> CheckValues = new Dictionary<string, Tuple<TestDateTimeSqlServerModel, TestDateTimeSqlServerModel>>();

        [ClassInitialize()]
        public static void ClassInitialize(TestContext testContext)
        {
            using (var sqlConnection = new SqlConnection(ConnectionString))
            {
                sqlConnection.Open();
                using (var sqlCommand = sqlConnection.CreateCommand())
                {
                    sqlCommand.CommandText = $"IF OBJECT_ID('{TableName}', 'U') IS NOT NULL DROP TABLE [{TableName}];";
                    sqlCommand.ExecuteNonQuery();

                    sqlCommand.CommandText = $"CREATE TABLE [{TableName}]( [Id] [int] NOT NULL, [Start] [datetime] NULL)";
                    sqlCommand.ExecuteNonQuery();
                }
            }
        }

        [ClassCleanup()]
        public static void ClassCleanup()
        {
            using (var sqlConnection = new SqlConnection(ConnectionString))
            {
                sqlConnection.Open();
                using (var sqlCommand = sqlConnection.CreateCommand())
                {
                    sqlCommand.CommandText = $"IF OBJECT_ID('{TableName}', 'U') IS NOT NULL DROP TABLE [{TableName}];";
                    sqlCommand.ExecuteNonQuery();
                }
            }
        }

        [TestMethod]
        public void DateTimeTest1()
        {
            SqlTableDependency<TestDateTimeSqlServerModel> tableDependency = null;

            Expression<Func<TestDateTimeSqlServerModel, bool>> expression = p => p.Start >= _now;
            ITableDependencyFilter filterExpression = new SqlTableDependencyFilter<TestDateTimeSqlServerModel>(expression);

            try
            {
                tableDependency = new SqlTableDependency<TestDateTimeSqlServerModel>(ConnectionString, filter: filterExpression);
                tableDependency.OnChanged += TableDependency_Changed;
                tableDependency.Start();

                Thread.Sleep(5000);

                var t = new Task(ModifyTableContent);
                t.Start();
                t.Wait(20000);
            }
            finally
            {
                tableDependency?.Dispose();
            }

            Assert.AreEqual(_counter, 2);
            Assert.AreEqual(1, _insertedId);
            Assert.AreEqual(1, _deletedId);
        }

        private void TableDependency_Changed(object sender, RecordChangedEventArgs<TestDateTimeSqlServerModel> e)
        {
            _counter++;

            switch (e.ChangeType)
            {
                case ChangeType.Insert:
                    _insertedId = e.Entity.Id;

                    break;
                case ChangeType.Delete:
                    _deletedId = e.Entity.Id;
                    break;
            }
        }

        private void ModifyTableContent()
        {
            var yesterday = DateTime.Now.AddDays(-3);

            using (var sqlConnection = new SqlConnection(ConnectionString))
            {
                sqlConnection.Open();
                using (var sqlCommand = sqlConnection.CreateCommand())
                {
                    sqlCommand.CommandText = $"INSERT INTO [{TableName}] ([Id], [Start]) VALUES (1, @today)";
                    sqlCommand.Parameters.AddWithValue("@today", _now);
                    sqlCommand.ExecuteNonQuery();
                    Thread.Sleep(500);

                    sqlCommand.Parameters.Clear();
                    sqlCommand.CommandText = $"INSERT INTO [{TableName}] ([Id], [Start]) VALUES (2, @yesterday)";
                    sqlCommand.Parameters.AddWithValue("@yesterday", yesterday);
                    sqlCommand.ExecuteNonQuery();
                    Thread.Sleep(500);

                    sqlCommand.CommandText = $"DELETE from [{TableName}]";
                    sqlCommand.ExecuteNonQuery();
                    Thread.Sleep(500);
                }
            }
        }
    }
}